package com.suredy.app.porject.ctrl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.suredy.app.porject.constants.BidStatus;
import com.suredy.app.porject.constants.FlowStatus;
import com.suredy.app.porject.constants.QuotationType;
import com.suredy.app.porject.constants.UserFileType;
import com.suredy.app.porject.ctrl.flow.FlowCtrl;
import com.suredy.app.porject.ctrl.flow.FlowCtrlForProject;
import com.suredy.app.porject.ctrl.view.ViewRoleCtrl;
import com.suredy.app.porject.ctrl.view.ViewRoleCtrlForBid;
import com.suredy.app.porject.formdata.FormDataForBidResult;
import com.suredy.app.porject.model.Bid;
import com.suredy.app.porject.model.BidAgency;
import com.suredy.app.porject.model.BidFile;
import com.suredy.app.porject.model.BidMoney;
import com.suredy.app.porject.model.BidResult;
import com.suredy.app.porject.model.Biddinger;
import com.suredy.app.porject.model.vo.BidEditModel;
import com.suredy.app.porject.service.BidAgencySrv;
import com.suredy.app.porject.service.BidFileSrv;
import com.suredy.app.porject.service.BidMoneySrv;
import com.suredy.app.porject.service.BidSrv;
import com.suredy.app.porject.service.BiddingerSrv;
import com.suredy.app.porject.service.ProjectCompany;
import com.suredy.app.porject.service.ProjectConstants;
import com.suredy.app.porject.tools.FileTool;
import com.suredy.core.helper.ApplicationContextHelper;
import com.suredy.core.mvc.model.MessageModel;
import com.suredy.security.entity.OrgEntity;
import com.suredy.security.entity.UserEntity;

/**
 * 招标view控制器
 * 
 * @author VIVID.G
 * @since 2015-10-12
 * @version v0.1
 */
@Controller
@RequestMapping("/bid")
public class BidCtrl extends FlowCtrl {

	private final static Logger log = LoggerFactory.getLogger(BidCtrl.class);

	@Autowired
	private FileTool fileTool;

	@Autowired
	private BidSrv bidSrv;

	@Autowired
	private BidFileSrv bidFileSrv;

	@Autowired
	private BidMoneySrv bidMoneySrv;

	@Autowired
	private BiddingerSrv biddingerSrv;

	@Autowired
	private BidAgencySrv bidAgencySrv;

	@Autowired
	private ProjectConstants constants;

	@Autowired
	private ProjectCompany company;

	@RequestMapping(value = "/create/{companyIndex}", method = RequestMethod.GET)
	public String createBid(@PathVariable int companyIndex, Model model) {
		String view = "app/bid/bid-create";

		ViewRoleCtrl roles = new ViewRoleCtrl(this.getRoles(), this.getUser());

		model.addAttribute("roles", roles);

		String company = this.company.getCompanyBy(companyIndex);
		if (StringUtils.isBlank(company))
			company = this.getUser().getOrgName();
		model.addAttribute("ownCompany", company);

		if (!roles.isCreateBid() || companyIndex != roles.getCompanyIndex()) {
			model.addAttribute("cannotcreate", true);
			return view;
		}

		model.addAttribute("biddingers", this.getBiddingers());
		model.addAttribute("bidAgencys", this.getBidAgencys());
		model.addAttribute("bidTypes", this.constants.getBidTypes(null));
		model.addAttribute("bidWays", this.constants.getBidWays(null));
		model.addAttribute("bidQuotationType", this.constants.getBidQuotationType(null));

		return view;
	}

	@RequestMapping(value = "/create", method = RequestMethod.POST)
	@ResponseBody
	public MessageModel createBid(Bid bid, @RequestParam(value = "serviceFile", required = false) MultipartFile serviceFile, @RequestParam(value = "doFile", required = false) MultipartFile doFile, @RequestParam(value = "file", required = false) MultipartFile[] file) {
		if (bid == null)
			return new MessageModel(false, "无效的招标信息！", null);

		// 初始化状态
		if (bid.getStatus() == null)
			bid.setStatus(BidStatus.B0001_IN_BIDDING);

		// 资金关联
		if (bid.getMoney() != null)
			for (BidMoney m : bid.getMoney()) {
				m.setBid(bid);
			}

		// 初始化流程
		this.createBidFlowInfo(bid, new UserEntity(this.getUser().getId()), FlowStatus.FS1000_BID_CREATED);

		bid.setFlowStatus(FlowStatus.FS1000_BID_CREATED);

		Bid data = this.bidSrv.save(bid);

		if (data == null || StringUtils.isBlank(data.getId()))
			return new MessageModel(false, "保存招标信息失败！", null);

		// 招标文件
		if (serviceFile != null)
			this.saveFile(serviceFile, data.getId(), UserFileType.F100_BID_SERVER_FILE);

		// 投标文件
		if (doFile != null)
			this.saveFile(doFile, data.getId(), UserFileType.F101_BID_DO_FILE);

		// 保存文件
		if (file != null)
			for (MultipartFile f : file) {
				this.saveFile(f, data.getId(), UserFileType.Z900_OTHER);
			}

		return new MessageModel(true, "操作成功！", data.getId());
	}

	@RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
	public String editBidForm(@PathVariable String id, Model model) {
		String view = "app/bid/bid-edit";

		if (StringUtils.isBlank(id)) {
			model.addAttribute("invalid", true);
			return view;
		}

		Bid data = this.bidSrv.get(id);

		if (data == null) {
			model.addAttribute("invalid", true);
			return view;
		}

		// 编辑人员必须为创建人且处于活动阶段
		if (data.getFlowStatus() == null || !data.getFlowStatus().equals(FlowStatus.FS1000_BID_CREATED)) {
			model.addAttribute("data", data);
			model.addAttribute("cannotedit", true);
			return view;
		}

		model.addAttribute("biddingers", this.getBiddingers());
		model.addAttribute("bidAgencys", this.getBidAgencys());
		model.addAttribute("bidTypes", this.constants.getBidTypes(null));
		model.addAttribute("bidWays", this.constants.getBidWays(null));
		model.addAttribute("bidQuotationType", this.constants.getBidQuotationType(null));

		List<String> ownCompany = this.company.getAllCompany();
		if (ownCompany == null || ownCompany.isEmpty()) {
			ownCompany = new ArrayList<String>();
			ownCompany.add(this.getUser().getOrgName());
		}

		model.addAttribute("ownCompany", ownCompany);

		model.addAttribute("data", data);

		return view;
	}

	@RequestMapping(value = "/edit", method = RequestMethod.POST)
	@ResponseBody
	public Object editBid(BidEditModel bid) {
		if (bid == null || StringUtils.isBlank(bid.getId()))
			return new MessageModel(false, "无效的招标信息！", null);

		Bid data = this.bidSrv.get(bid.getId());

		if (data == null || StringUtils.isBlank(data.getId()))
			return new MessageModel(false, "保存招标信息失败！", null);

		try {
			PropertyUtils.copyProperties(data, bid);
		} catch (Exception e) {
			return new MessageModel(false, "保存招标信息失败！\n" + e.getMessage(), null);
		}

		data = this.bidSrv.update(data);

		if (data == null || StringUtils.isBlank(data.getId()))
			return new MessageModel(false, "保存招标信息失败！", null);

		return new MessageModel(true, "操作成功！", data.getId());
	}

	@RequestMapping(value = "/view/{id}", method = RequestMethod.GET)
	public String viewBid(@PathVariable String id, Model model) {
		String view = "app/bid/bid-view";

		if (StringUtils.isBlank(id))
			return view;

		Bid data = this.bidSrv.get(id);

		model.addAttribute("roles", new ViewRoleCtrlForBid(data, this.getUser(), this.getRoles()));

		if (data == null)
			return view;

		model.addAttribute("data", data);

		return view;
	}

	@RequestMapping(value = "/list/{status}", method = RequestMethod.GET)
	public String list(@PathVariable BidStatus status, Integer page, Integer pageSize, Model model) {
		String view = "app/bid/bid-list";

		if (status == null)
			return view;

		Bid search = new Bid();
		search.setStatus(status);

		if (page == null || page <= 0)
			page = 1;

		if (pageSize == null || pageSize <= 0)
			pageSize = 30;

		List<Bid> data = this.bidSrv.readByEntity(search, page, pageSize);

		if (data == null || data.isEmpty())
			return view;

		model.addAttribute("status", status);
		model.addAttribute("data", data);
		model.addAttribute("page", page);
		model.addAttribute("pageSize", pageSize);
		model.addAttribute("count", this.bidSrv.getCountByEntity(search));

		return view;
	}

	@RequestMapping(value = "/bid-result/{bidId}/{status}/{qt}", method = RequestMethod.GET)
	public String bidResultForm(@PathVariable String bidId, @PathVariable BidStatus status, @PathVariable QuotationType qt, Model model) {
		String view = "app/bid/bid-result";

		if (StringUtils.isBlank(bidId) || status == null || qt == null) {
			model.addAttribute("invalid", true);
			return view;
		}

		model.addAttribute("bidId", bidId);
		model.addAttribute("status", status);
		model.addAttribute("qt", qt);

		return view;
	}

	@RequestMapping(value = "/add-result", method = RequestMethod.POST)
	@ResponseBody
	public Object recordBidResult(FormDataForBidResult data, @RequestParam(value = "bidNoticeFile", required = false) MultipartFile bidNoticeFile) {
		if (data == null)
			return new MessageModel(false, "操作失败，数据无效！", null);

		BidResult result = data.getResult();
		Date reOpenTime = data.getReOpenTime();
		List<BidMoney> money = data.getMoney();

		if (result == null || result.getStatus() == null || result.getBid() == null || StringUtils.isBlank(result.getBid().getId()))
			return new MessageModel(false, "操作失败，招标结果信息无效！", null);

		// 中标但是没有上传中标通知书
		if (BidStatus.B0003_WIN.equals(result.getStatus()) && bidNoticeFile == null)
			return new MessageModel(false, "操作失败，请选择中标通知书！", null);

		// 中标但是没有填写中标服务费
		if (BidStatus.B0003_WIN.equals(result.getStatus()) && (money == null || money.size() != 1))
			return new MessageModel(false, "操作失败，请选择中标通知书！", null);

		// 中标和未中标都要填写中标价
		if (BidStatus.B0003_WIN.equals(result.getStatus()) || BidStatus.B0004_LOSE.equals(result.getStatus())) {
			if (result.getFinalMoney() == null)
				return new MessageModel(false, "操作失败，[中标价]必须填写！", null);
		}

		// 重投的时候必须填写开标时间
		if (BidStatus.B0002_MISS_REBID.equals(result.getStatus())) {
			if (reOpenTime == null)
				return new MessageModel(false, "操作失败，[开标时间]必须填写！", null);
		}

		Bid bid = this.bidSrv.get(result.getBid().getId());

		if (bid == null)
			return new MessageModel(false, "操作失败，无法找到招标数据！", null);

		// 重新设置招标信息
		result.setBid(bid);
		result.setTime(new Date());
		result.setOpeningTime(bid.getOpeningTime()); // 记录之前的开标时间

		// 中标后设置中标服务费
		if (BidStatus.B0003_WIN.equals(result.getStatus())) {
			BidMoney m = money.get(0);
			m.setBid(bid);
			m.setSource(bid.getBidAgencyInfo().getAgency().getCompany());
			bid.getMoney().add(m);
		}

		// 中标的时候需要自动添加公司信息
		if (BidStatus.B0003_WIN.equals(result.getStatus()) && StringUtils.isBlank(result.getWinCompany()))
			result.setWinCompany(bid.getOwnCompany());

		if (bid.getResult() == null)
			bid.setResult(new ArrayList<BidResult>());

		if (reOpenTime != null)
			bid.setOpeningTime(reOpenTime);

		bid.setStatus(result.getStatus());
		bid.getResult().add(result);

		bid = this.bidSrv.update(bid);

		if (bid == null)
			return new MessageModel(false, "操作失败，无法保存您提供的信息！", null);

		// 流标和未中标需要更新流程状态为completed状态
		if (Arrays.asList(BidStatus.B0004_LOSE/* , BidStatus.B0005_MISS */).contains(bid.getStatus())) {
			FlowCtrlForProject fcfp = ApplicationContextHelper.getBeanByType(FlowCtrlForProject.class);
			MessageModel mm = fcfp.changeStatusForBid(bid.getId(), FlowStatus.FS1002_BID_COMPLETED);

			if (!mm.isSuccess())
				return mm;
		}

		// 上传中标通知书
		if (bidNoticeFile != null && !this.saveFile(bidNoticeFile, bid.getId(), UserFileType.F103_BID_NOTICE_FILE))
			return new MessageModel(false, "保存中标通知书失败！", null);

		return new MessageModel(true, "操作成功！", result);
	}

	@RequestMapping(value = "/payout/{bidId}", method = RequestMethod.GET)
	public String payoutForm(@PathVariable String bidId, Model model) {
		String view = "app/bid/bid-payout";

		if (StringUtils.isBlank(bidId)) {
			model.addAttribute("invalid", true);
			return view;
		}

		model.addAttribute("bidId", bidId);
		model.addAttribute("payoutNames", this.constants.getBidPayoutNames(null));
		model.addAttribute("payoutNameDicKey", ProjectConstants.DK_BID_PAYOUT_NAME);

		return view;
	}

	@RequestMapping(value = "/add-payout", method = RequestMethod.POST)
	@ResponseBody
	public Object addPayout(BidMoney money) {
		if (money == null || money.getBid() == null || StringUtils.isBlank(money.getBid().getId()))
			return new MessageModel(false, "无效的付款信息！", null);

		if (StringUtils.isBlank(money.getName()) || money.getTotal() == null || money.getTime() == null)
			return new MessageModel(false, "[资金名目]、[支出金额]和[支出日期]不能为空！", null);

		money = this.bidMoneySrv.save(money);

		if (money == null || StringUtils.isBlank(money.getId()))
			return new MessageModel(false, "保存费用支出信息失败！", null);

		return new MessageModel(true, "操作成功！", money);
	}

	@RequestMapping(value = "/upload-bid-file/{bidId}", method = RequestMethod.GET)
	public String uploadBidFileForm(@PathVariable String bidId, Model model) {
		String view = "app/bid/bid-file-upload";

		if (StringUtils.isBlank(bidId)) {
			model.addAttribute("invalid", true);
			return view;
		}

		model.addAttribute("bidId", bidId);

		return view;
	}

	@RequestMapping(value = "/upload-bid-file/{bidId}", method = RequestMethod.POST)
	@ResponseBody
	public Object uploadBidFile(@PathVariable String bidId, @RequestParam(value = "file", required = false) MultipartFile files) {
		if (files == null)
			return new MessageModel(false, "请选择需要上传的文件！", null);

		if (StringUtils.isBlank(bidId))
			return new MessageModel(false, "无效的招标信息！", null);

		if (!this.saveFile(files, bidId, UserFileType.F101_BID_DO_FILE)) {
			return new MessageModel(false, "文件保存失败！", null);
		}

		return new MessageModel(true, "操作成功！", null);
	}

	@RequestMapping(value = "/common-file-upload/{bidId}/{fileType}", method = RequestMethod.POST)
	public String commonFileUploadForm(@PathVariable String bidId, @PathVariable UserFileType fileType, String suffix, Model model) {
		String view = "app/bid/common-file-upload";

		if (StringUtils.isBlank(bidId) || fileType == null) {
			model.addAttribute("invalid", true);
			return view;
		}

		model.addAttribute("bidId", bidId);
		model.addAttribute("fileType", fileType);
		model.addAttribute("suffix", suffix);

		return view;
	}

	@RequestMapping(value = "/common-file-upload", method = RequestMethod.POST)
	@ResponseBody
	public Object commonFileUpload(String bidId, UserFileType fileType, @RequestParam(value = "file", required = false) MultipartFile file) {
		if (file == null)
			return new MessageModel(false, "请选择需要上传的文件！", null);

		if (StringUtils.isBlank(bidId))
			return new MessageModel(false, "无效的招标信息！", null);

		if (fileType == null)
			return new MessageModel(false, "无法识别文件类型！", null);

		if (!this.saveFile(file, bidId, fileType))
			return new MessageModel(false, "文件保存失败！", null);

		return new MessageModel(true, "操作成功！", null);
	}

	@RequestMapping(value = "/delete-by-ids", method = RequestMethod.POST)
	@ResponseBody
	public Object delete(String[] ids) {
		if (ids == null || ids.length <= 0)
			return new MessageModel(true, "操作成功！", null);

		this.bidSrv.deleteByIds(ids);

		return new MessageModel(true, "操作成功！", null);
	}

	private List<Biddinger> getBiddingers() {
		Biddinger search = new Biddinger();
		search.setOwner(new OrgEntity());
		search.getOwner().setId(this.getUser().getOrgId());

		List<Biddinger> data = this.biddingerSrv.readByEntity(search);

		return data == null || data.isEmpty() ? null : data;
	}

	private List<BidAgency> getBidAgencys() {
		BidAgency search = new BidAgency();
		search.setOwner(new OrgEntity());
		search.getOwner().setId(this.getUser().getOrgId());

		List<BidAgency> data = this.bidAgencySrv.readByEntity(search);

		return data == null || data.isEmpty() ? null : data;
	}

	private boolean saveFile(MultipartFile file, String bidId, UserFileType type) {
		if (file == null || StringUtils.isBlank(bidId))
			return false;

		if (type == null)
			type = UserFileType.Z900_OTHER;

		Bid bid = new Bid();
		bid.setId(bidId);

		String fileName = file.getOriginalFilename();

		String suffix = fileName.substring(fileName.lastIndexOf('.'));
		fileName = fileName.substring(0, fileName.lastIndexOf('.'));

		try {
			File tmp = this.fileTool.store(file.getInputStream(), bidId);

			BidFile data = new BidFile();

			data.setType(type);
			data.setBid(bid);
			data.setFileName(fileName);
			data.setFilePath(this.fileTool.relativelyPath(tmp));
			data.setSize(file.getSize());
			data.setSuffix(suffix);
			data.setUploadTime(new Date());
			data.setUserName(this.getUser().getName());

			data = this.bidFileSrv.save(data);

			return data != null && !StringUtils.isBlank(data.getId());
		} catch (IOException e) {
			log.error("Receive file error", e);
		}

		return false;
	}

}
